//
// Created by ct on 2020/10/28.
//

#ifndef NETTOP_EPOLL_STDIN_H
#define NETTOP_EPOLL_STDIN_H

#include <sys/epoll.h>
#include <unistd.h>
#include "utils.h"
namespace utils {
    class epoll_stdin {
        int efd_;
    public:
        epoll_stdin() : efd_(epoll_create1(0)){
            if(-1 == efd_) {
                throw nettop::runtime_error("Can't created epoll fd: ") << strerror(errno);
                // 添加标准输入
                struct epoll_event event = {0};
                event.events = EPOLLIN|EPOLLPRI|EPOLLERR;
                event.data.fd = STDIN_FILENO;
                if(epoll_ctl(efd_, EPOLL_CTL_ADD, STDIN_FILENO, &event)) {
                    close(efd_);
                    throw nettop::runtime_error("Can't add STDIN to epoll fd: ") << strerror(errno);
                }
            }
        }

        // 需要刷新时返回true
        bool do_io(const size_t msec_tmout){
            struct epoll_event	event = {0};
            const int		fds = epoll_wait(efd_, &event, 1, msec_tmout);
            if(0 == fds) return false;
            else if (0 > fds) {
                if(EINTR == errno)
                    return false;
                throw nettop::runtime_error("Error in epoll_wait: ") << strerror(errno);
            }
            // 我们最多只能得到一个事件
            if (event.data.fd == STDIN_FILENO) {
                char		buf[128];
                // read input line
                const int	rb = read(STDIN_FILENO, &buf, 128);
                if(rb > 0) {
                    return on_data(buf, rb);
                } else throw nettop::runtime_error("Error in reading STDIN: ") << strerror(errno);
            }
            return false;
        }
        virtual bool on_data(const char* p ,const size_t sz) const = 0;
        virtual ~epoll_stdin() {
            close(efd_);
        }

    };
}
#endif //NETTOP_EPOLL_STDIN_H
